﻿#include <iostream>
#include <mutex>
#include <thread>

template <typename T>
class SharedPointer
{
public:
	SharedPointer(T* ptr = nullptr);
	T* operator->();
	T& operator*();
	~SharedPointer();
	SharedPointer(SharedPointer<T>&);
	SharedPointer<T>& operator=(SharedPointer<T>&);
	T* Get() const;
	void Release();
	void AddRef();
	int use_count() const;
	void SubRef();

private:
	T* _ptr = nullptr;
	int* _pCount = nullptr;
	std::mutex* _pMutex;
};


template <typename T>
class WeakPointer
{
public:
	WeakPointer(T* ptr = nullptr);
	WeakPointer(const SharedPointer<T>& sp);
	WeakPointer<T>& operator=(const SharedPointer<T>& sp);
	T& operator*();
	T* operator->();
	int use_count() const;
	~WeakPointer();

private:
	T* _ptr;
};

class ListNode
{
public:
	// ListNode *_prev = nullptr;
	// ListNode *_next = nullptr;
	// SharedPointer<ListNode> _prev;
	// SharedPointer<ListNode> _next;
	// std::shared_ptr<ListNode> _prev;
	// std::shared_ptr<ListNode> _next;
	//std::weak_ptr<ListNode> _prev;
	//std::weak_ptr<ListNode> _next;
	WeakPointer<ListNode> _prev;
	WeakPointer<ListNode> _next;
	int _val = 0;
};

template <typename T>
WeakPointer<T>::WeakPointer(T* ptr)
	:_ptr(ptr)
{}

template <typename T>
WeakPointer<T>::WeakPointer(const SharedPointer<T>& sp)
{
	_ptr = sp.Get();
}

template <typename T>
WeakPointer<T>& WeakPointer<T>::operator=(const SharedPointer<T>& sp)
{
	_ptr = sp.Get();

	return *this;
}

template <typename T>
int WeakPointer<T>::use_count() const
{
	return _ptr.DisplayCount();
}

template <typename T>
WeakPointer<T>::~WeakPointer()
{
	std::cout << "WeakPointer<T>::~WeakPointer()" << std::endl;
}

template <typename T>
T& WeakPointer<T>::operator*()
{
	return *_ptr;
}

template <typename T>
T* WeakPointer<T>::operator->()
{
	return _ptr;
}

template <typename T>
SharedPointer<T>::SharedPointer(T* ptr)
	: _ptr(ptr)
	, _pMutex(new std::mutex)
{
	_pCount = new int(0);
	AddRef();
}

template <typename T>
T* SharedPointer<T>::operator->()
{
	return _ptr;
}

template <typename T>
T& SharedPointer<T>::operator*()
{
	return *_ptr;
}

template <typename T>
SharedPointer<T>::~SharedPointer()
{
	Release();
}

template <typename T>
T* SharedPointer<T>::Get() const
{
	return _ptr;
}

template <typename T>
void SharedPointer<T>::AddRef()
{
	_pMutex->lock();
	++(*_pCount);
	_pMutex->unlock();
}

template <typename T>
void SharedPointer<T>::SubRef()
{
	_pMutex->lock();
	--(*_pCount);
	_pMutex->unlock();
}

template <typename T>
SharedPointer<T>::SharedPointer(SharedPointer<T>& sp)
	: _pCount(sp._pCount), _ptr(sp._ptr), _pMutex(sp._pMutex)
{
	AddRef();
}

template <typename T>
SharedPointer<T>& SharedPointer<T>::operator=(SharedPointer<T>& sp)
{
	if (_ptr != sp._ptr)
	{
		Release();
		_ptr = sp._ptr;
		_pCount = sp._pCount;
		_pMutex = sp._pMutex;
		sp.AddRef();
	}
	return *this;
}

template <typename T>
void SharedPointer<T>::Release()
{
	// 打印引用计数的次数
	// std::cout << "_count: " << (*_pCount) << std::endl;
	SubRef();
	if ((*_pCount) == 0 && _ptr != nullptr)
	{
		delete _ptr;
		delete _pCount;
		delete _pMutex;

		_ptr = nullptr;
		_pCount = nullptr;
		_pMutex = nullptr;
		std::cout << "The _ptr has been deleted!" << std::endl;
	}
	else
	{
		// 打印当前资源情况
		std::cout << "The _ptr can't be deleted!" << std::endl;
		std::cout << "_count: " << (*_pCount) << std::endl;
	}
}

template <typename T>
int SharedPointer<T>::use_count() const
{
	return *_pCount;
}


void Test7()
{
	// 假设有这样一个场景：
	// ListNode* node1 = new ListNode;
	// ListNode* node2 = new ListNode;
	// node1->_next = node2;
	// node2->_prev = node1;

	// delete node1;
	// delete node2;
	// node1 = nullptr;
	// node2 = nullptr;

	// 如果我希望使用智能指针来管理资源呢？
	//SharedPointer<ListNode> ptr1(new ListNode);
	//SharedPointer<ListNode> ptr2(new ListNode);

	//ptr1->_next = ptr2;
	//ptr2->_prev = ptr1;
	//ptr1->_prev = ptr2;
	//ptr2->_next = ptr1;

	// 程序结束之后，我们发现该程序并没有释放new出来的空间
	// 为什么呢？
	// 首先是ptr2调用析构函数，发现此时的_pCount指向的int为3，所以ptr2自减之后就直接结束了。
	// 注意：可能大家会疑惑，析构函数进行析构的时候会自动调用自定义类型成员对象的析构函数吗？
	// 为什么这里没有调用两份拷贝的SharedPtr析构函数的？
	// 注意：析构函数进行析构的时候，会调用自定义类型成员对象的析构函数，但是成员对象指针是不会调用析构函数的
	// 所以SharedPtr中的_ptr指向的资源需要在SharedPtr中的析构函数中释放(或者另作处理)
	// 为了解决这种循环引用的问题，C++标准库中提供了weak_ptr专门处理这种情况
	//std::shared_ptr<ListNode> ptr1(new ListNode);
	//std::shared_ptr<ListNode> ptr2(new ListNode);

	//std::cout << "ptr1: " << ptr1.use_count() << std::endl;
	//std::cout << "ptr2: " << ptr2.use_count() << std::endl;

	//ptr1->_next = ptr2;
	//ptr2->_prev = ptr1;

	//std::cout << "ptr1: " << ptr1.use_count() << std::endl;
	//std::cout << "ptr2: " << ptr2.use_count() << std::endl;

	//std::shared_ptr<ListNode> ptr3(new ListNode);
	//std::shared_ptr<ListNode> ptr4(new ListNode);

	//std::cout << "ptr3: " << ptr3.use_count() << std::endl;
	//std::cout << "ptr4: " << ptr4.use_count() << std::endl;

	//ptr3->_next = ptr4;
	//ptr4->_prev = ptr3;

	//std::cout << "ptr3: " << ptr3.use_count() << std::endl;
	//std::cout << "ptr4: " << ptr4.use_count() << std::endl;

	SharedPointer<ListNode> ptr3(new ListNode);
	SharedPointer<ListNode> ptr4(new ListNode);

	std::cout << "ptr3: " << ptr3.use_count() << std::endl;
	std::cout << "ptr4: " << ptr4.use_count() << std::endl;

	ptr3->_next = static_cast<WeakPointer<ListNode>>(ptr4);
	ptr4->_prev = static_cast<WeakPointer<ListNode>>(ptr3);

	std::cout << "ptr3: " << ptr3.use_count() << std::endl;
	std::cout << "ptr4: " << ptr4.use_count() << std::endl;
}

class A
{
public:
	~A()
	{
		std::cout << "	~A()" << std::endl;
	}
};

class B
{
public:
	B()
	{
		std::cout << "	B()" << std::endl;
	}
	~B()
	{
		std::cout << "	~B()" << std::endl;
	}
	A a;
	A* pa = new A;
};

void Test8()
{
	// B b;
	B* ptr = new B; // new的时候会调用构造(new会调用构造函数)
	delete ptr; // delete的时候会调用析构函数
	// A* p = new A;
	// b.pa = p;
	// delete p;
}

int main()
{
	// Test1();
	// Test2();
	// Test3();
	// Test4();
	// Test5();
	// Test6();
	Test7();
	// Test8();
	return 0;
}
